//$Id: YujingAI.java 207 2010-11-07 14:25:38Z liangyj20030161@yahoo.com.sg $

package builders;
import java.util.ArrayList;
import java.util.Random;

/**
 * This class simulates action of a Player, and is able to make decisions on its own
 * @author Liang Yujing
 *
 */
public class YujingAI extends AI{
	private final int HOMEBASE_ONE = 0;
	private final int HOMEBASE_TWO = 9;
	private final int HOMEBASE_THREE = 18;
	private final int HOMEBASE_FOUR = 27;
	
	public YujingAI(String name, int homebase) {
		super(name, homebase);
	}
	
	/**
	 * This part returns Logic the tile that AI has chosen to move to
	 * AI has 2/3 chances of being smart, and 1/3 chance of being stupid so that AI will not be *too* smart
	 * @param GameState g
	 * @return int: number of the tile that AI wants to move to
	 */
	public int selectTile(GameState g){
		Random r = new java.util.Random();
		int rand = r.nextInt(6);
		
		switch (rand){
		case 0 : return stupidChooseTileAI(g);
		case 3 : return stupidChooseTileAI(g);
		default : return smartChooseTileAI(g);
		}
	}
	
	/**
	 * This part returns Logic the name of the building that AI chooses
	 * AI has 2/3 chances of being smart, and 1/3 chance of being stupid so that AI will not be *too* smart
	 * Note that it is possible to return null, if the AI cannot build any Buildings
	 * @param GameState g 
	 * @return Building: the Building that AI wants to choose to build
	 */
	public Building selectBuilding(GameState g){
		Random r = new java.util.Random();
		int rand = r.nextInt(6);
		
		switch (rand){
		case 1 : return stupidChooseBuildingAI(g);
		case 4 : return stupidChooseBuildingAI(g);
		default : return smartChooseBuildingAI(g);
		}
	}

	/**
	 * Stupid AI always chooses a random tile that it can move to 
	 * @param GameState g
	 * @return int: number of the tile that AI wants to move to
	 */
	private int stupidChooseTileAI(GameState g){
		ArrayList<Integer> tilesYouCanMoveTo = g.getTilesYouCanMoveTo();
		int sizeOfRandomness = tilesYouCanMoveTo.size();
		
		Random r = new java.util.Random();
		int rand = r.nextInt(sizeOfRandomness);
		
		return tilesYouCanMoveTo.get(rand);
	}
	
	/**
	 * Stupid AI always chooses a random building that it can move to
	 * possible to return null if there are no buildings that AI can build
	 * @param GameState g
	 * @return Building: name of the Building that AI wants to build
	 */
	private Building stupidChooseBuildingAI(GameState g){
		ArrayList<Building> buildingsYouCanBuild = g.getBuildingsYouCanBuild();
		int sizeOfRandomness = buildingsYouCanBuild.size();
		
		if (sizeOfRandomness == 0){
			return null;
		}
		
		Random r = new java.util.Random();
		int rand = r.nextInt(sizeOfRandomness);
		
		return buildingsYouCanBuild.get(rand);
	}
	
	/**
	 * Smart AI makes choice of tile depending on circumstances
	 * @param GameState g
	 * @return int: number of the tile that AI wants to move to
	 */
	private int smartChooseTileAI(GameState g){		
		ArrayList<Building> buildingsAICanBuild = g.getBuildingsYouCanBuild();
		ArrayList<Building> buildingsAvailable = g.getAllBuildingsAvailableForBuilding();
		ArrayList<Integer> tilesYouCanMoveTo = g.getTilesYouCanMoveTo();
		int dieValue = g.getMovementActivityPoints() - 1;
		int movementPoints = 0;
		int activityPoints;
		int maxPoints = 0;
		int tileToBeChosen = -1;
		boolean fromNewBuildings = false;
		ArrayList<Building> newBuildingsAICanBuild = new ArrayList<Building>();
		ArrayList<Integer> mappedTileNumber = new ArrayList<Integer>();
		
		/*
		 * 1. for each tile that AI can move to, calculate the new amount of resources that AI can get if it moves there
		 * 2. check if AI can build any buildings with new amount of resources
		 * 3. if there are any buildings that AI can build, add the tile number to mappedTileNumber
		 */
		for (int i = 0; i < tilesYouCanMoveTo.size(); i++){
			int currentTileNumber = tilesYouCanMoveTo.get(i);

			if (currentTileNumber != HOMEBASE_ONE
					&& currentTileNumber != HOMEBASE_TWO
					&& currentTileNumber != HOMEBASE_THREE
					&& currentTileNumber != HOMEBASE_FOUR){
				
				movementPoints++;
				activityPoints = dieValue - movementPoints + 1;
				Tile tile = g.getTileManager().squareToTile(currentTileNumber);
				Player.Resource resourceAffected = tile.execute(activityPoints).getResourceThatIsAffected();
				int resourceFromTile = tile.execute(activityPoints).getAmountToIncrease();
				
/*				System.out.println(tile.execute(activityPoints).getErrorPresent());
				System.out.println(activityPoints + " " + dieValue + " " + movementPoints);
				if(resourceAffected == null){
					System.out.println("null");
				}*/
				
				int currentAmountOfResource = super.getCurrentResourceAmount(resourceAffected);		
				int newAmountOfResource = currentAmountOfResource + resourceFromTile;

				for (Building b : buildingsAvailable) {
					boolean canBuild = false;
					for (BuildingRequirement r : b.getBuildingRequirementList()) {
						if (resourceAffected.equals(r.getResources()) &&  newAmountOfResource >= r.getAmount()) {
							canBuild = true;						
						}
						if (canBuild && buildingsAvailable.contains(b)){
							newBuildingsAICanBuild.add(b);
							mappedTileNumber.add(currentTileNumber);
						}
					}
				}
			}
		}
		
		/*
		 * for all the new buildings that AI can potentially build, 
		 * check which building gives the maximum number of points
		 */
		for (Building b : newBuildingsAICanBuild){
			if (b.getPoints() > maxPoints){
				maxPoints = b.getPoints();
				tileToBeChosen = mappedTileNumber.get(newBuildingsAICanBuild.indexOf(b));
				fromNewBuildings = true;
			}
		}
		
		/*
		 * for all the buildings that AI could have built without any additional resources, 
		 * check if any building can give more points that potential buildings
		 */
		for (Building b : buildingsAICanBuild){
			if (b.getPoints() > maxPoints){
				maxPoints = b.getPoints();
				fromNewBuildings = false;
			}
		}
		
		/*
		 * if some tile can be chosen and building that can be built is not from current resources,
		 * return that particular tile number
		 * else, just return stupid AI
		 */
		if(fromNewBuildings && (tileToBeChosen != -1)){
			return tileToBeChosen;
		} else return stupidChooseTileAI(g);
		
		
	}
	
	/**
	 * Smart AI chooses the building that gives the maximum number of points
	 * possible to return null for name if there are no buildings that AI can build
	 * @param GameState g
	 * @return Building: name of the Building that AI wants to build
	 */
	private Building smartChooseBuildingAI(GameState g){
		ArrayList<Building> buildingsAICanBuild = g.getBuildingsYouCanBuild();
		Building result = null;
		int maxPoints = 0;
		
		for (Building building: buildingsAICanBuild){
			if (building.getPoints() > maxPoints){
				maxPoints = building.getPoints();
				result = building;
			}
		}
		
		return result;
		
	}
	
	/**
	 * Added for UnitTestingAI and aiTestCase
	 * No other classes are supposed to call this method
	 * @param currentResources
	 */
	public void setCurrentResourcesList(int[] currentResources){
		this.currentResourcesList = currentResources;
	}
	
	
	/**
	 * For UnitTestingAi and aiTestCase to use only
	 * @param GameState g
	 * @return int: number of the tile that AI wants to move to
	 */
	public int chooseTileThinkSmart(GameState g){
		return smartChooseTileAI(g);
	}
	
	/**
	 * For UnitTestingAi and aiTestCase to use only
	 * @param GameState g
	 * @return int: number of the tile that AI wants to move to
	 */
	public int chooseTileThinkStupid(GameState g){
		return g.getTilesYouCanMoveTo().get(0);
	}
	
	/**
	 * For UnitTestingAi and aiTestCase to use only
	 * @param GameState g
	 * @return Building: the Building that AI wants to choose to build
	 */
	public Building chooseBuildingThinkSmart(GameState g){
		return smartChooseBuildingAI(g);
	}
	
	/**
	 * For UnitTestingAi and aiTestCase to use only
	 * @param GameState g
	 * @return String: name of the Building that AI wants to build
	 */
	public String chooseBuildingThinkStupid(GameState g){
		if (g.getBuildingsYouCanBuild().size() != 0){
			return g.getBuildingsYouCanBuild().get(0).getName();
		} else return null;
	}
	
/*	public static void main(String[] args){
		AI ai = new AI("lala", 3);
		ai.setCurrentResourceAmount(Resource.DUNG, 4);
		ai.setCurrentResourceAmount(Resource.GLASS, 7);
		for (int i = 0; i < 6; i++){
			System.out.println(ai.currentResourcesList[i]);
		}
	}
*/
}
